#ifndef __utils_h__
#define __utils_h__

#include "mtrand.hh"
#include "stacktrace.hh"

#include "fadbad.hh"
#include <cmath>

static unsigned int rng_seed = 123456789;
static MTRand random_generator (rng_seed); // mt19937 is a standard //mersenne_twister_engine

void timestamp ( );

double *r8mat_uniform_01_new ( int m, int n, int *seed ) ;

double r8vec_sum ( int n, double a[] );

double *r8vec_uniform_01_new ( int n, int *seed );

void r8ge_fss ( int n, double a[], int nb, double b[] );

double *r8mat_copy_new ( int m, int n, double a1[] );

double r8mat_det_4d ( double a[4*4] );

int r8mat_solve ( int n, int rhs_num, double a[] );

double *r8mat_mv ( int m, int n, double a[], double x[] );

#define i4_min(n1,n2) (n2<n1?n2:n1)

#define i4_max(n1,n2) (n2<n1?n1:n2)

#define r8_abs(val) (val<0?-val:val)

void bandwidth_mesh ( int element_order, int element_num, int element_node[],
  int *ml, int *mu, int *m );

void bandwidth_var ( int element_order, int element_num, int element_node[],
  int node_num, int var_node[], int var_num, int var[], int *ml, int *mu, 
  int *m );

inline
void generate_seed()
{
  MTRand_int32 irand;
  rng_seed = irand() ; // std::chrono::system_clock::now().time_since_epoch().count();
  random_generator.seed(rng_seed);
}

inline
double generate_random()
{
  return random_generator() ;
}

namespace femlib {
  
  template<typename T>
  T pow(T value, T exponent)
  {
    T val = std::pow(value, exponent);
    return val;
  }

}

#endif // #ifndef __utils_h__
